package genedit.controller;


import genedit.gui.GMainFrame;
import genedit.gui.propertyDialogs.AggregationLinkDialog;
import genedit.gui.propertyDialogs.AssociationLinkDialog;
import genedit.gui.propertyDialogs.ClassModelDialog;
import genedit.gui.propertyDialogs.CompositionLinkDialog;
import genedit.gui.propertyDialogs.GeneralizationLinkDialog;
import genedit.gui.propertyDialogs.InterfaceModelDialog;
import genedit.model.Workspace;
import genedit.model.graph.GraphElement;
import genedit.model.graph.Link;
import genedit.model.graph.classModel.AggregationLink;
import genedit.model.graph.classModel.AssociationLink;
import genedit.model.graph.classModel.ClassModel;
import genedit.model.graph.classModel.CompositionLink;
import genedit.model.graph.classModel.GeneralizationLink;
import genedit.model.graph.classModel.InterfaceModel;
import genedit.view.graph.ElementPainter;
import genedit.view.graph.GraphWorkArea;

import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.util.Iterator;

/**
 * Klasa enkapsulira ponaÅ¡anje u stanju selekcije, koje predstavlja osnovno
 * stanje. Pored dodavanja i uklanjanja elemenata iz selekcije ovo stanje je
 * zaduÅ¾eno za pripremu i postavljanja nekoliko drugih stanja kao aktivno
 * stnaje.
 * 
 * @author Nikola
 * @version 1.1 19/12/13
 */
public class SelectionState extends State {
	int mouseButton = 0;

	public void mouseClicked(MouseEvent e) {
		if (e.getClickCount() == 2 && !e.isConsumed()) {
		     e.consume();
		     if(context.getView().getModel().getSelectedElements().size()==1 && (context.getView().getModel().getSelectedElements().get(0) instanceof ClassModel)) {
		     ClassModelDialog dialog = new ClassModelDialog(GMainFrame.getInstance(), context.getView().getModel().getSelectedElements().get(0));
				dialog.setVisible(true);
		     }	
		     else if(context.getView().getModel().getSelectedElements().size()==1 && (context.getView().getModel().getSelectedElements().get(0) instanceof InterfaceModel)) {
			     InterfaceModelDialog dialog = new InterfaceModelDialog(GMainFrame.getInstance(), context.getView().getModel().getSelectedElements().get(0));
					dialog.setVisible(true);
			     }	
		     else if(context.getView().getModel().getSelectedElements().size()==1 && (context.getView().getModel().getSelectedElements().get(0) instanceof AssociationLink)) {
			     AssociationLinkDialog dialog = new AssociationLinkDialog(GMainFrame.getInstance(), (AssociationLink)context.getView().getModel().getSelectedElements().get(0));
					dialog.setVisible(true);
			     }	
		     else if(context.getView().getModel().getSelectedElements().size()==1 && (context.getView().getModel().getSelectedElements().get(0) instanceof GeneralizationLink)) {
			     GeneralizationLinkDialog dialog = new GeneralizationLinkDialog(GMainFrame.getInstance(), (GeneralizationLink)context.getView().getModel().getSelectedElements().get(0));
					dialog.setVisible(true);
			     }
		     else if(context.getView().getModel().getSelectedElements().size()==1 && (context.getView().getModel().getSelectedElements().get(0) instanceof AggregationLink)) {
			     AggregationLinkDialog dialog = new AggregationLinkDialog(GMainFrame.getInstance(), (AggregationLink)context.getView().getModel().getSelectedElements().get(0));
					dialog.setVisible(true);
			     }
		     else if(context.getView().getModel().getSelectedElements().size()==1 && (context.getView().getModel().getSelectedElements().get(0) instanceof CompositionLink)) {
			     CompositionLinkDialog dialog = new CompositionLinkDialog(GMainFrame.getInstance(), (CompositionLink)context.getView().getModel().getSelectedElements().get(0));
					dialog.setVisible(true);
			     }
		}
	}

	/**
	 * Ova metoda brine o prelasku u stanje laso selekcije (u sluÄ�aju da nema
	 * elemenata na poziciji miÅ¡a), odnosno move state (u sluÄ�aju da ima).
	 */
	public void mouseDragged(MouseEvent e) {
		if (mouseButton == 1) {
			Point position = e.getPoint();
			context.pointToUserSpace(position);

			if (context != null) {
				GraphElement currentElement = getElementAtPosition(position);
				if (currentElement == null) {
					context.getController().setCurrentState(
							new LassoSelectionState(context, position));
				} else {
					context.getController().setCurrentState(new MoveState(context, position));
				}
			}
		}
	}

	/**
	 * Ova metoda brine o dodavanju i uklanjanju elemenata iz selekcije. TakoÄ‘e,
	 * ovde se vrÅ¡i prelazak u stanje rotacije i skaliranja ukoliko su ispunjeni
	 * uslovi.
	 */
	public void mousePressed(MouseEvent e) {
		mouseButton = e.getButton();
		Point position = e.getPoint();
		context.pointToUserSpace(position);

		if (context != null) {
			GraphElement currentElement = null;

			if (e.getButton() == MouseEvent.BUTTON1) {
				currentElement = getElementAtPosition(position);
			}
			if (e.getButton() == MouseEvent.BUTTON1 && !e.isControlDown()) {
				if (currentElement != null) {
					if (!context.getView().getModel().getSelectedElements()
							.contains(currentElement)) {

						context.getView().getModel().removeAllSelectedElements();
						context.getView().getModel().addSelectedElements(currentElement);
					} else {
						 boolean isResize = false;
							for(GraphElement element : context.getView().getModel().getSelectedElements()){ 
								if( !(element instanceof Link) && 
									context.getHandleHandler().getHandleForPoint(element, position, context.getTransformation().getScaleX())
									!= null) {
										 context.getController().setCurrentState(
												 new ResizeState(context,  context.getHandleHandler().getHandleForPoint(element, position, context.getTransformation().getScaleX()), position));
										 isResize = true;
								}
							}
							if(!isResize){ 
								context.getController().setCurrentState(new MoveState(context, position));
							}
					}
				} else {
					boolean isRotate = false;
					for (GraphElement element : context.getView().getModel().getSelectedElements()) {
						if (!(element instanceof Link)
								&& context.getHandleHandler().getHandleForPoint(element, position,
								context.getTransformation().getScaleX()) == context
										.getHandleHandler().getHandleForRotate()) {
							context.getController().setCurrentState(new RotateState(context, element, position));
							isRotate = true;
						}
						else if( !(element instanceof Link) && 
								context.getHandleHandler().getHandleForPoint(element, position, context.getTransformation().getScaleX())
								!= null) {
									 context.getController().setCurrentState(
											 new ResizeState(context,  context.getHandleHandler().getHandleForPoint(element, position, context.getTransformation().getScaleX()), position));
									 isRotate = true;
							}
					}
					if (!isRotate) {
						context.getView().getModel().removeAllSelectedElements();
					}
				}
			} else if (e.getButton() == MouseEvent.BUTTON1 && e.isControlDown()) {
				if (currentElement != null) {
					if (!context.getView().getModel().getSelectedElements()
							.contains(currentElement)) {
						context.getView().getModel().addSelectedElements(currentElement);
					} else {
						context.getView().getModel().removeSelectedElements(currentElement);
					}
				}
			}
			context.repaint();
			currentElement = null;

		}

	}

	/**
	 * Metoda se brine o pomeranju elemenata prilikom pritiska na strelice
	 * (ukoliko selekcija nije prazna), odnosno skrolovanju (ukoliko selekcija
	 * jeste prazna).
	 */
	public void keyPressed(KeyEvent e) {
		int key = e.getKeyCode();

		if (key == KeyEvent.VK_DOWN || key == KeyEvent.VK_LEFT || key == KeyEvent.VK_UP
				|| key == KeyEvent.VK_RIGHT) {
			int x = 0, y = 0;
			int moveFactor = 50;
			switch (key) {
			case KeyEvent.VK_DOWN:
				y = moveFactor;
				break;
			case KeyEvent.VK_UP:
				y = -moveFactor;
				break;
			case KeyEvent.VK_LEFT:
				x = -moveFactor;
				break;
			case KeyEvent.VK_RIGHT:
				x = moveFactor;
				break;
			}

			if (Workspace.getInstance().getActiveDocument().getModel().getSelectedElements().size() > 0) {
				MoveCommand newMove = new MoveCommand(true, x, y);
				newMove.setDocument(Workspace.getInstance().getActiveDocument());
				newMove.setMovedElements(Workspace.getInstance().getActiveDocument().getModel()
						.getSelectedElements());
				newMove.setMoveByX(x);
				newMove.setMoveByY(y);
				Workspace.getInstance().getActiveDocument().getModel().getInvoker()
						.executeCommand(newMove);
			} else {
				GraphWorkArea workArea = ((GraphWorkArea) Workspace.getInstance()
						.getActiveDocument().getWorkArea());
				//workArea.setTranslateX(workArea.getTranslateX() - x);
				//workArea.setTranslateY(workArea.getTranslateY() - y);
				int valueScrollh = context.getScrollHorizontal().getValue();
				if(((valueScrollh + x >= context.getScrollHorizontal().getMinimum())) && ((valueScrollh + x <= context.getScrollHorizontal().getMaximum()))){										
					context.getScrollHorizontal().setValue(valueScrollh+x);
					valueScrollh = context.getScrollHorizontal().getValue();
					context.sethScrollValue(valueScrollh);
					workArea.setTranslateX(workArea.getTranslateX() - x);
				}
				int valueScrollv = context.getScrollVertical().getValue();
				if(((valueScrollv + y >= context.getScrollVertical().getMinimum())) && ((valueScrollv + y <= context.getScrollVertical().getMaximum()))){					
					context.getScrollVertical().setValue(valueScrollv+y);
					valueScrollv = context.getScrollVertical().getValue();
					context.setvScrollValue(valueScrollv);
					workArea.setTranslateY(workArea.getTranslateY() - y);
				}
				workArea.setupTransformation();
				workArea.repaint();
			}
		}

	}

	/**
	 * Metoda brine o izgledu kursora prilikom kretanju po radnoj povrÅ¡ini (za
	 * skaliranje, rotaciju).
	 */
	public void mouseMoved(MouseEvent arg0) {
		if (context != null) {
			Point2D point = arg0.getPoint();
			context.pointToUserSpace(point);
			context.setMouseCursor(point);
		}
	}

	public SelectionState(GraphWorkArea context) {
		super(context);
		if (context != null)
			context.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}

	/**
	 * Metoda vraÄ‡a element koji se nalazi na poziciji kursora, ili null ukoliko
	 * nema elementa iznad.
	 * 
	 * @param position
	 *            poloÅ¾aj kursora
	 * @return element na poziciji; null ako nema niÄ�ega.
	 */
	private GraphElement getElementAtPosition(Point2D position) {
		if (context != null) {
			Iterator<ElementPainter> iter = context.getView().getIteratorElementPainters();
			while (iter.hasNext()) {
				ElementPainter painter = iter.next();
				if (painter.isElementAt(position))
					return painter.getElement();
			}
		}
		return null;
	}

}